let graph = new Graph.graph

let makefileDep = ref []
let moduleList = ref []
let i = ref 0
let tmpModule = ref []
let parsed = ref []
let stringDep = ref ""
let stringMod = ref ""

let lowerFirstLetter word = 
	let lower = String.sub word 0 1 in
	let newWord = ((String.lowercase lower)^(String.sub word 1 ((String.length word) - 1))) in
	newWord 
	
let reconstructPath path = (Sys.getcwd ())^"/"^path^".ml"

let ocamllist = ["Arg"; "Array"; "ArrayLabels"; "Buffer"; "Callback"; "Char"; "Complex"; "Digest"; "Filename"; "Format"; "Gc"; "Genlex"; "Hashtbl"; "Int32"; "Int64"; "Lazy"; "Lexing"; "List"; "ListLabels"; "Map"; "Marshal"; "MoreLabels"; "Nativeint"; "Oo"; "Parsing"; "Printexc"; "Printf"; "Queue"; "Random"; "Scanf"; "Set"; "Sort"; "Stack"; "StdLabels"; "Stream"; "String"; "StringLabels"; "Sys"; "Weak"]


let rec deleteDoublon = function
	[] -> []
       |e::l when (List.exists (fun x -> x=e) l) -> deleteDoublon l
       |e::l -> e::(deleteDoublon l)


let rec deleteGtkModule = function
    [] -> []
   |e::l when e.[0] = 'G' -> makefileDep := ("lablgtk")::(!makefileDep); deleteGtkModule l
   |e::l when List.exists (fun x -> x=e) ocamllist -> deleteGtkModule l
   |e::l when (Sys.file_exists (reconstructPath (lowerFirstLetter e)))->  (lowerFirstLetter e)::(deleteGtkModule l)
   |e::l -> makefileDep := (lowerFirstLetter e)::(!makefileDep); deleteGtkModule l
    

let rec matchModule buffer path = 
    try
        let reg = Str.regexp "[^A-z,\\.,\\-]+\\([A-Z][A-z]*\\)\\." in 
    i := Str.search_forward reg buffer !i;
    begin
    let word = (Str.matched_group 1 buffer) in   
    if(lowerFirstLetter word <> path) then 
    begin
      moduleList := !moduleList @ [word]; 
      (if not(List.exists (fun x -> x=word) !tmpModule) then
      tmpModule := !tmpModule @ [word]);
    end;
    i := !i + (String.length word);
    matchModule buffer path;
    i := 0
    end
    with Not_found -> ()

let loadText path  = 
  let text = open_in path in
  let length = in_channel_length text in
  let str = String.create length in
    really_input text str 0 length;
    close_in text;
   str


let parse path = if ( not (List.exists (fun x -> x=path) !parsed)) then
  begin
    parsed := (!parsed)@[path];
    matchModule (loadText (reconstructPath path)) path;
    moduleList := (deleteGtkModule (deleteDoublon (!moduleList)));
   (* print_endline ("\n- Begin parse in : "^path);*)
    tmpModule := (deleteGtkModule !tmpModule);
    let tmp = ref (!tmpModule) in
   (* print_endline ("\nadd arc : "^path^" "^(string_of_int (List.length !tmpModule)));
    print_string ("add_succ : "); List.iter (fun x -> print_string x) !tmp;*)
    graph#add_arc path tmp;
    tmpModule := [];    
  end


let rec recurs l1 l2 =
   if(List.sort String.compare !moduleList = List.sort String.compare l1) then 
     begin
	match l2 with
     [] -> ()
   |e::l2 when (Sys.file_exists (reconstructPath e)) -> parse e; recurs l1 l2
   |e::l2 -> recurs l1 l2
     end




let writeMakefile _ = 
	List.iter (fun e -> stringDep := ((!stringDep)^e^".cmxa ")) !makefileDep;
	List.iter (fun e -> stringMod := ((!stringMod)^e^".ml ")) !moduleList;
	let makefile = open_out "MakefileTest" in
	output_string makefile "# Makefile\n";
	output_string makefile "# Qui fonctionne\n\n";

	output_string makefile "PRG = test\n\n";
	output_string makefile "# Fichiers dans l'ordre\n";
	output_string makefile ("ML ="^(!stringMod)^"\n\n") ;

	output_string makefile "CMO=${ML:.ml=.cmo}\n";
	output_string makefile "CMX=${ML:.ml=.cmx}\n";
	output_string makefile "CMI=${ML:.mli=.cmi}\n\n";

	output_string makefile "OCAMLFLAGS = -I +lablgtk2\n";
	output_string makefile ("OCAMLLD = "^(!stringDep)^" -ccopt -L.\n");
	output_string makefile "OCAMLOPT = ocamlopt.opt\n";
	output_string makefile "OCAMLC = ocamlc.opt\n";
	output_string makefile "OCAMLDEP = ocamldep\n\n";

	output_string makefile "${PRG}: ${CMX}\n";
	output_string makefile "${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLLD} -o $@ ${CMX}\n";
	output_string makefile "make clean\n\n";

	output_string makefile ".SUFFIXES: .ml .mli .cmo .cmx .cmi\n\n";

	output_string makefile ".ml.cmx: \n";
	output_string makefile "${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLLD} -c $<\n\n";

	output_string makefile ".ml.cmo: \n";
	output_string makefile "${OCAMLC} -c $<\n\n";

	output_string makefile ".mli.cmi:" ;
	output_string makefile "${OCAMLC} -c $<\n\n";

	output_string makefile "clean:\n";
	output_string makefile "rm -f *~ *.o *.cm? *mli\n\n";
	output_string makefile "fullclean: clean\n";
	output_string makefile "rm -f .depend ${PRG}\n\n";
	output_string makefile "depend: .depend\n";
	output_string makefile ".depend: ${ML} ${MLI}\n";
	output_string makefile "rm -f .depend\n";
	output_string makefile "${OCAMLDEP} ${ML} ${MLI} > .depend\n\n";	 
	output_string makefile "include .depend\n"
   
let generateGraph path =  
	makefileDep := [];
	moduleList :=  [];
	i :=  0;
	tmpModule := [];
	parsed := [];
	stringDep :="";
	stringMod := "";
	graph#reset_graph;
    moduleList := path::(!moduleList);
    parse path;
    while((List.sort String.compare !moduleList) <> (List.sort String.compare !parsed)) do
	let tmp = !moduleList in	
	recurs tmp tmp;
        moduleList := (deleteGtkModule (deleteDoublon (!moduleList)));
    done;
    moduleList := List.rev !moduleList;
    makefileDep := deleteDoublon !makefileDep

let generateMakefile path =  
    generateGraph path;
    print_endline "\nmoduleList =";
    List.iter (fun x -> print_endline x) !moduleList;
    print_endline "\nmakefileDep =";
    List.iter (fun x -> print_endline x) !makefileDep;
    writeMakefile ();
    print_endline "\n";
    print_endline !stringDep;
    print_endline !stringMod;   
    print_endline "\nMakefileTest written\n"

let printGraph path =  generateGraph path; print_endline "\ngraph :\n"; graph#print_graph

let parcLarg path =  generateGraph path; print_endline ("\nParcours Largeur depuis "^path^" =\n");
    graph#parcLarg path print_endline

let parcProf path = generateGraph path ;print_endline ("\nParcours Profondeur depuis "^path^" =\n");
    graph#parcProf path print_endline

